#include "IfBuilder.h"

#include "ScriptCompiler/ScriptFileContext.h"

#include "ScriptCompiler/AST/IfNode.h"
#include "ScriptCompiler/AST/ExpressionNode.h"
#include "ScriptCompiler/AST/SentenceBlockNode.h"

#include "ScriptCompiler/ASTBuilder/ExpressionBuilder.h"
#include "ScriptCompiler/ASTBuilder/SentenceBlockBuilder.h"


CIfBuilder::CIfBuilder(std::shared_ptr<CScriptFileContext> InContext)
{
    Context = InContext;
    Result = std::make_shared<CIfNode>(InContext);
}

bool CIfBuilder::ReadCurentToken()
{
    //check 'if'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::If)
        {
            Context->RaiseError(10064,Token,U"Expect 'if' here");
            return false;
        }

        Result->If = Token;

        Context->CurrentTokenIndex++;
    } 

    //check '('
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftParentheses)
        {
            Context->RaiseError(10065,Token,U"Expect '(' here");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    //find ')'
    uint64_t RightParenthesesIndex;
    {
        auto RightParenthesesPos=FindPairedParentheses(Context);
        if(!RightParenthesesPos)
        {
            //raise error, require ')'
            Context->RaiseError(10066,Context->GetCurrentToken(),U"Expected paired ')' ");
            return false;
        }
        RightParenthesesIndex=*RightParenthesesPos;
    }

    //check condition
    {
        auto ExpressionBuilder = std::make_shared<CExpressionBuilder>(Context,RightParenthesesIndex);
        if (!ExpressionBuilder->ReadCurentToken())
        {
            return false;
        }
        Result->Condition = ExpressionBuilder->Result;
    }

    //check ')'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::RightParentheses)
        {
            Context->RaiseError(10067,Token,U"Expect ')' here");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    //make sure next token is '{'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftBrace)
        {
            Context->RaiseError(10155,Token,U"Expect a '{' here, to start if body");
            return false;
        }
        Context->CurrentTokenIndex++;
    }

    //find paired '}'
    uint64_t RightBraceIndex;
    {
        auto RightBracePos = FindPairedBrace(Context);
        if (!RightBracePos)
        {
            //raise error, require '}'
            Context->RaiseError(10156,Context->GetCurrentToken(),U"Expected paired '}' ");
            return false;
        }
        RightBraceIndex = *RightBracePos;
    }

    //build body 
    {
        auto SentenceBlockBuilder = std::make_shared<CSentenceBlockBuilder>(Context,RightBraceIndex);
        if (!SentenceBlockBuilder->ReadCurentToken())
        {
            return false;
        }

        Result->TrueBranch = SentenceBlockBuilder->Result;
    }

    //skip }
    assert(Context->CurrentTokenIndex==RightBraceIndex);
    Context->CurrentTokenIndex++;


    //check 'else'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type == EScriptTokenType::Else)
        {
            Context->CurrentTokenIndex++;
        }
        else
        {
            //no else branch, finished
            return true;
        }
    }

    //check 'else if' or 'else'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type == EScriptTokenType::If)
        {
            //else if
            auto IfBuilder = std::make_shared<CIfBuilder>(Context);
            if (!IfBuilder->ReadCurentToken())
            {
                return false;
            }

            Result->FalseBranch=std::make_shared<CSentenceBlockNode>(Context);
            Result->FalseBranch->Sentences.Add(IfBuilder->Result);
            return true;
        }
        else
        {
            //else
            auto Token = Context->GetCurrentToken();
            if (Token->Type != EScriptTokenType::LeftBrace)
            {
                Context->RaiseError(10157,Token,U"Expect '{' here, to start else body");
                return false;
            }
            Context->CurrentTokenIndex++;

            //find paired '}'
            uint64_t RightBraceIndex;
            {
                auto RightBracePos = FindPairedBrace(Context);
                if (!RightBracePos)
                {
                    //raise error, require '}'
                    Context->RaiseError(10158,Context->GetCurrentToken(),U"Expected paired '}' ");
                    return false;
                }
                RightBraceIndex = *RightBracePos;
            }

            //build body 
            {
                auto SentenceBlockBuilder = std::make_shared<CSentenceBlockBuilder>(Context,RightBraceIndex);
                if (!SentenceBlockBuilder->ReadCurentToken())
                {
                    return false;
                }

                Result->FalseBranch = SentenceBlockBuilder->Result;
            }


            //skip } at end of else
            assert(Context->GetCurrentToken()->Type==EScriptTokenType::RightBrace);
            Context->CurrentTokenIndex++;

            return true;
        }
    }
}